﻿using Idenmpotency;

namespace Microsoft.AspNetCore.Idenmpotency
{
    /// <summary>
    /// 幂等性检查器(模板模式-控制反转)
    /// </summary>
    public class DefultIdenmpotencyChecker: IIdenmpotencyChecker
    {
        /// <summary>
        /// 请求仓储
        /// </summary>
        private IIdenmpotencyRequestRepositroy _repositroy;

        /// <summary>
        /// 策略抽象工厂
        /// </summary>
        private IIdenmpotencyRequestHandlerFactroy _factory;

        /// <summary>
        /// 构造函数
        /// </summary>
        /// <param name="repositroy"></param>
        /// <param name="handlerFactroy"></param>
        public DefultIdenmpotencyChecker(IIdenmpotencyRequestRepositroy repositroy, IIdenmpotencyRequestHandlerFactroy handlerFactroy)
        {
            if (repositroy == null) throw new ArgumentNullException(nameof(repositroy));
            if (handlerFactroy == null) throw new ArgumentNullException(nameof(repositroy));
            this._repositroy = repositroy;
            this._factory = handlerFactroy;
        }

        /// <summary>
        /// 检查
        /// </summary>
        /// <typeparam name="TRequestId"></typeparam>
        /// <param name="request"></param>
        /// <returns></returns>
        public async Task CheckAsync(IIdenmpotencyRequest request, CancellationToken token = default)
        {
            var handler=this._factory.Handler;
            try
            {
                //预检查，成功：继续检查，失败：不继续 
                if (!await handler.PreCheckHandleAsync(request, token)) return;     
                //是否存在：存在：重复性处理，失败：首次处理
                var isExist = await _repositroy.IsExistAscyn(request);
                if (isExist)                                                    
                {
                    await handler.ReiteratedRequestHandleAsync(request, token); 
                }
                else
                {
                    await _repositroy.SaveAsync(request);
                    await handler.FirstRequestHandleAsync(request, token);
                }
                
            }
            catch (AggregateException e)
            {
                throw e;
            }

        }
    }
}
